﻿using MongoDB.Driver;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.Entities.ProductInvolvement;
using Sustainalytics.Entities.SustainableProducts;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.ScreeningTool.Synchronization.Handlers
{
    public class SustainableProductsDataHandler : IHandler<SustainableProductsData>, IHasClientFacingProduct
    {
        private static readonly IEnumerable<string> _indicatorFieldsToInclude = new[]
        {
            nameof(SustainableProductsIndicator.ClientFacingProducts),
            nameof(SustainableProductsIndicator.IndicatorSymbol),
            nameof(SustainableProductsIndicator.CategorySymbol),
            nameof(SustainableProductsIndicator.CategoryOfInvolvementType),
            nameof(SustainableProductsIndicator.CategoryOfInvolvementDescription),
            nameof(SustainableProductsIndicator.LevelOfInvolvement),
            nameof(SustainableProductsIndicator.HasLevelOfInvolvement),
            nameof(SustainableProductsIndicator.RevenuePercentage),
            nameof(SustainableProductsIndicator.ProductRevenue),
            nameof(SustainableProductsIndicator.ProductInvolvementAnalysis),
            nameof(SustainableProductsIndicator.RevenueAnalysis),
            nameof(SustainableProductsIndicator.RevenueAnalysisSource),
            nameof(SustainableProductsIndicator.FinancialYear)
        }.Select(x => $"Indicators.{x}").ToList();

        public ClientFacingProduct ClientFacingProduct { get; set; }

        public ProjectionDefinition<SustainableProductsData> GetProjection(ProjectionDefinitionBuilder<SustainableProductsData> builder) => builder
            .Include(x => x.Currency)
            .Include(_indicatorFieldsToInclude);

        public IEnumerable<ExtraElement> GetExtraElements(SustainableProductsData entity)
        {
            var indicators = entity.Indicators
                .Where(x => x.ClientFacingProducts == null || x.ClientFacingProducts.Contains(ClientFacingProduct))
                .ToList();

            var overallSolutionsInvolvement = indicators
                .Where(x => x.CategoryOfInvolvementType == CategoryOfInvolvementType.Yes)
                .Select(x => x.IndicatorSymbol)
                .Distinct()
                .OrderBy(x => x)
                .JoinStrings(";");

            return indicators
                .SelectMany(indicator => GetExtraElements(indicator, entity))
                .Concat(new ExtraElementList
                {
                    { "Overall Reported Currency",     entity.Currency             },
                    { "Overall Solutions Involvement", overallSolutionsInvolvement },
                });
        }

        private static IEnumerable<ExtraElement> GetExtraElements(SustainableProductsIndicator involvement, SustainableProductsData entity)
        {
            var key = involvement.IndicatorSymbol + " " + involvement.CategorySymbol;

            if (involvement.CategoryOfInvolvementType == CategoryOfInvolvementType.No)
                return new ExtraElementList();

            if (involvement.CategoryOfInvolvementType == CategoryOfInvolvementType.NotResearched)
                return NotResearchedExtraElements(key);

            var categoryAndLevelOfInvolvement = involvement.CategorySymbol + "-" + involvement.LevelOfInvolvement.Id;

            return new ExtraElementList
            {
                { $"{key} Category & Level of Involvement", categoryAndLevelOfInvolvement                },
                { $"{key} Category of Involvement",         involvement.CategoryOfInvolvementDescription },
                { $"{key} Category of Involvement Id",      involvement.CategorySymbol                   },
                { $"{key} Level of Involvement Id",         involvement.LevelOfInvolvement.Id            },
                { $"{key} Level of Involvement Range",      involvement.GetLevelOfInvolvement()          },
                { $"{key} Revenue Percentage",              involvement.RevenuePercentage                },
                { $"{key} Revenue",                         involvement.ProductRevenue                   },
                { $"{key} Involvement Analysis",            involvement.ProductInvolvementAnalysis       },
                { $"{key} Revenue Analysis",                involvement.RevenueAnalysis                  },
                { $"{key} Revenue Analysis Source",         involvement.RevenueAnalysisSource            },
                { $"{key} Financial Year",                  involvement.FinancialYear                    },
                { $"{key} Overall Reported Currency",       entity.Currency                              },
            };
        }

        private static IEnumerable<ExtraElement> NotResearchedExtraElements(string key)
            => new ExtraElementList
            {
                { $"{key} Category of Involvement", CategoryOfInvolvementType.NotResearched },
            };
    }
}
